package com.wyg.server;

import com.wyg.protocol.RPCRequest;
import com.wyg.protocol.RPCResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: WYG
 * @time: 2020/10/24 18:36
 */

public class RPCServerHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LoggerFactory.getLogger(RPCServerHandler.class);

    private final Map<String, Object> handlerMap;

    public RPCServerHandler(Map<String, Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        RPCResponse rpcResponse = new RPCResponse();
        RPCRequest rpcRequest = (RPCRequest) msg;
        rpcResponse.setRequestId(rpcRequest.getRequestId());
        try {
            Object handle = handle(rpcRequest);
            // System.out.println(handle);
            rpcResponse.setResult(handle);
        } catch (Throwable throwable) {
            rpcResponse.setError(throwable);
        }
        ctx.writeAndFlush(rpcResponse);
    }

    private Object handle(RPCRequest request) throws Throwable {
        String className = request.getInterfaceName();
        Object serviceBean = handlerMap.get(className);

        Class<?> serviceClass = serviceBean.getClass();
        String methodName = request.getMethodName();
        Class<?>[] parameterTypes = request.getParamsTypes();
        Object[] parameters = request.getParams();

        FastClass serviceFastClass = FastClass.create(serviceClass);
        FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);
        return serviceFastMethod.invoke(serviceBean, parameters);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("server caught exception", cause);
        ctx.close();
    }
}
